﻿
using Dapper;
using hentity;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace hwms {
    /**
   *┌────────────────────────────────────────────────┐
   *│　描    述：Component                                                    
   *│　作    者：sgj                                              
   *│　版    本：1.0                                              
   *│　创建时间：2020/9/2 11:28:16                        
   *└────────────────────────────────────────────────┘
   **/
    public  class SelectLocUtil {
        private const int MAX_WEIGHT = 100000000;
     
        public static CoreWhLoc selectLoc< CSD>(IDbConnection connection ,IDbTransaction transaction ,List<CSD> stockDetailsList)where CSD : AbsCoreStockDetail, new() {

            long itemId = CsdUtil.getItemId(stockDetailsList);
            
            long itemClassifyId = getItemClassifyId(connection ,transaction ,itemId);
            if( itemClassifyId == 0 ) {
                throw new Exception(itemId + "的分类未找到");
            }
            long goodDiff = getGroup(stockDetailsList ,itemClassifyId ,connection ,transaction);
            //一个物料类别对应多个区域
            CoreWhLoc loc = getBastCoreWhLoc(itemClassifyId ,goodDiff ,connection ,transaction);
            return loc;
        }


        public static CoreWhLoc getBastCoreWhLoc(long itemClassifyId ,long goodDiff ,IDbConnection conn ,IDbTransaction trans) {
            CoreWhLoc beforeLoc = locBeforeSelect(itemClassifyId ,goodDiff);
            if( beforeLoc != null ) {
                return beforeLoc;
            }
            AreaLocWeightDto dto = null;
            string sql = @"select * from core_classify_Area  where classify_Id=@classifyId order by Priority ";
            //一个物料类别对应多个区域 查询物料优先放在哪个区域
            List<CoreClassifyArea> coreClassifyAreaList = conn.Query<CoreClassifyArea>(sql ,new {
                classifyId = itemClassifyId
            } ,trans).ToList();

            for( int j = 0;j < coreClassifyAreaList.Count;j++ ) {
                CoreClassifyArea areaDto = coreClassifyAreaList[j];
                List<CoreWhLoc> locList = CoreUtil.getLoc4SelectIn(areaDto.areaId ,-1 ,conn ,trans);
                if( locList.Count == 0 ) {
                    continue;
                }
                AreaLocWeightDto tmp = getAreaLocWeightDto(goodDiff ,areaDto.priority ,locList);
                tmp = locChangeWeight(itemClassifyId ,goodDiff ,tmp);
                if( tmp == null ) {
                    continue;
                }
                if( tmp.weight == MAX_WEIGHT && tmp.loc != null ) {//起到优化作用，减少无意义循环
                    return tmp.loc;
                }
                if( dto == null || tmp.weight > dto.weight ) {
                    dto = tmp;
                }
            }
            if( dto == null || dto.loc == null ) {
                return null;
            }

            return locFinally(dto);
        }
        protected static CoreWhLoc locBeforeSelect(long itemClassifyId ,long group) {
            return null;
        }
        protected static CoreWhLoc locFinally(AreaLocWeightDto dto) {
            return dto.loc;
        }
        protected static AreaLocWeightDto locChangeWeight(long itemClassifyId ,long group ,AreaLocWeightDto tmp) {
            return tmp;
        }
        protected static bool checkLast(List<CoreWhLoc> locList) {
            int count = 0;
            int relse = 0;
            foreach( CoreWhLoc loc in locList ) {
                if( loc.type != 1 ) {
                    count++;
                }
                if( loc.countStock < loc.Maxstock ) {
                    relse++;
                }
            }
            return count > 0 && relse <= 1;
        }
        protected static AreaLocWeightDto getAreaLocWeightDto(long goodDiff ,int priority ,List<CoreWhLoc> alllocList) {
            Dictionary<long ,List<CoreWhLoc>> coreWhLocDict = groupLoc(alllocList);

            AreaLocWeightDto max = null;
            foreach( var item in coreWhLocDict ) {
                List<CoreWhLoc> locList = item.Value;
                if( checkLast(locList) ) {
                    continue;
                }

                AreaLocWeightDto areaLocWeightDto = new AreaLocWeightDto();
                if( priority == 1 ) {
                    areaLocWeightDto.weight = MAX_WEIGHT;
                    CoreWhLoc loc = AllocateLoc(locList ,goodDiff);
                    areaLocWeightDto.loc = loc;
                    if( loc != null ) {
                        return areaLocWeightDto;
                    }
                } else if( priority == 2 ) {
                    areaLocWeightDto.weight = locList.Count();
                    areaLocWeightDto.loc = AllocateLoc(locList ,goodDiff);
                } else if( priority == 3 ) {
                    float count = 0;
                    foreach( CoreWhLoc loc in locList ) {
                        count += loc.countStock;
                    }
                    areaLocWeightDto.weight = ( int ) ((1 - count / locList.Count()) * MAX_WEIGHT);
                    areaLocWeightDto.loc = AllocateLoc(locList ,goodDiff);
                }
                if( areaLocWeightDto.loc == null ) {
                    continue;
                }
                if( max == null ) {
                    max = areaLocWeightDto;
                } else if( areaLocWeightDto.weight > max.weight ) {
                    max = areaLocWeightDto;
                }
            }
            return max;
        }
        protected static CoreWhLoc AllocateLoc(List<CoreWhLoc> locList ,long goodDiff) {
            CoreWhLoc loc= LocConfig.select(locList ,goodDiff);
            return afterSelect(loc,locList ,goodDiff);
        }

        protected static CoreWhLoc afterSelect(CoreWhLoc loc ,List<CoreWhLoc> locList ,long goodDiff) {
           
            return  loc;
        }
        protected static Dictionary<long ,List<CoreWhLoc>> groupLoc(List<CoreWhLoc> locList) {

            Dictionary<long ,List<CoreWhLoc>> coreWhLocDict = new Dictionary<long ,List<CoreWhLoc>>();
            foreach( CoreWhLoc coreWhLoc in locList ) {
                if( coreWhLocDict.ContainsKey(coreWhLoc.moveGroup) ) {
                    coreWhLocDict[coreWhLoc.moveGroup].Add(coreWhLoc);
                } else {
                    coreWhLocDict.Add(coreWhLoc.moveGroup ,new List<CoreWhLoc>() { coreWhLoc });
                }
            }
            return coreWhLocDict;
        }
        static public long getItemClassifyId(IDbConnection Connection ,IDbTransaction transaction ,long itemId) {
            string sql = @"select classify_Id classifyId from core_Item where id=@id ";
            var r = Connection.Query(sql ,new { id = itemId } ,transaction);
            long classifyId = ( long ) r.First().classifyId;
            return classifyId;
        }
        public static long getGroup<CSD>(List<CSD> stockDetailsList ,long itemClassifyId ,IDbConnection connection ,IDbTransaction transaction) where CSD : AbsCoreStockDetail, new() {
            String no =  stockDetailsList[0].itemId+"";
            return stockDetailsList[0].itemId * 1000000 + int.Parse(no == null?"0": no);

        }

    }
}
